package org.thinkin.springboot.compiler;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Collections;


public class DynamicCompiler {

    // 简单的Java源代码，我们打算编译并运行它
    static final String sourceTemplate = "${IMPORT_CODE} \n" +
            "public class ${CLASS_NAME} { \n" +
            "   public static void excecute() {\n" +
            "       ${JAVA_CODE}\n" +
            "   }\n" +
            "}";

    static final String outputDir = System.getProperty("user.dir")
            + File.separator + "target"
            + File.separator + "classes"
            + File.separator + "dynamicCompiler";

    static {
        File file = new File(outputDir);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    public static void compilerAndRun(String importCode, String sourceCode) throws Exception {
        // 获取系统Java编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        //初始化诊断收集器
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();

        // 使用标准文件管理器
        try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) {
            String dynamicClassName = "DynamicClassName_" + System.currentTimeMillis();
            String sourceCodeTemp = sourceTemplate.replace("${CLASS_NAME}", dynamicClassName);
            sourceCodeTemp = sourceCodeTemp.replace("${IMPORT_CODE}", importCode);
            sourceCodeTemp = sourceCodeTemp.replace("${JAVA_CODE}", sourceCode);
            // 创建一个Java源代码文件对象（内存中的）
            JavaFileObject file = new JavaSourceFromString(dynamicClassName, sourceCodeTemp);
            // 获取编译任务
            Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(file);
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics,
                    Arrays.asList("-d", outputDir), null, compilationUnits);
            // 执行编译
            boolean success = task.call();

            // 输出编译诊断信息
            if (!success) {
                StringBuilder sb = new StringBuilder();
                diagnostics.getDiagnostics().forEach(diag -> sb.append(String.format("Error on line %d in %s%n",
                        diag.getLineNumber(),
                        diag.getSource().toUri())));
                throw new RuntimeException(sb.toString());
            }
            else {
                // 编译成功，现在加载并执行类
                final ClassLoader loader = Thread.currentThread().getContextClassLoader();
                ClassLoader classLoader = AccessController.doPrivileged(
                        (PrivilegedAction<ClassLoaderImpl>) () -> new ClassLoaderImpl(loader, outputDir));
                Class<?> cls = classLoader.loadClass(dynamicClassName);
                Method mainMethod = cls.getMethod("excecute");
                mainMethod.invoke(null);
            }
        }
    }
}